part of '../repository.dart';

BuiltMap<String, dynamic> _migrateBackupContentFromSecondVersionToThirdOne({
  required BuiltMap<String, dynamic> backupContent,
}) {
  final migratedBackupContent = backupContent.rebuild((backupJson) {
    final lexicalItemProgressJson =
        Map.castFrom<dynamic, dynamic, String, dynamic>(backupJson['lexical_items_progress']);

    final brainBoostListItemMaps = List.castFrom<dynamic, Map>(backupJson['brain_boost_list']);

    final brainBoostListItemJsons = brainBoostListItemMaps.map((brainBoostListItemMap) {
      final brainBoostListItemJson =
          Map.castFrom<dynamic, dynamic, String, dynamic>(brainBoostListItemMap);
      return brainBoostListItemJson;
    }).toList();

    final learningQueueItemMaps = List.castFrom<dynamic, Map>(backupJson['learning_queue']);

    final learningQueueItemJsons = learningQueueItemMaps.map((learningQueueItemMap) {
      final learningQueueItemJson =
          Map.castFrom<dynamic, dynamic, String, dynamic>(learningQueueItemMap);
      return learningQueueItemJson;
    }).toList();

    final customLexicalItemMaps = List.castFrom<dynamic, Map>(backupJson['user_words']);

    final customLexicalItemJsons = customLexicalItemMaps.map((customLexicalItemMap) {
      final customLexicalItemJson =
          Map.castFrom<dynamic, dynamic, String, dynamic>(customLexicalItemMap);
      customLexicalItemJson.remove('type');
      return customLexicalItemJson;
    }).toList();

    final lexicalItemMetaMap = <String, Map>{};

    for (final lexicalItemProgressEntry in lexicalItemProgressJson.entries) {
      final lexicalItemMetaJson = <String, dynamic>{};

      final lexicalItemId = lexicalItemProgressEntry.key;
      final lexicalItemProgressMap = lexicalItemProgressEntry.value;

      Map<String, dynamic>? lexicalItemLearningQueueItemJson;
      for (final learningQueueItemJson in learningQueueItemJsons) {
        if (learningQueueItemJson['lexical_item_id'] == lexicalItemId) {
          lexicalItemLearningQueueItemJson = learningQueueItemJson;
          break;
        }
      }

      Map<String, dynamic>? lexicalItemBrainBoostListItemJson;
      for (final brainBoostListItemJson in brainBoostListItemJsons) {
        if (brainBoostListItemJson['lexical_item_id'] == lexicalItemId) {
          lexicalItemBrainBoostListItemJson = brainBoostListItemJson;
          break;
        }
      }

      if (lexicalItemProgressMap == null) {
        if (lexicalItemLearningQueueItemJson != null) {
          lexicalItemMetaJson['progress'] = {
            'type': 'learning',
            'learning_stages': [
              {
                'type': 'suspended',
                'learning_event': 'added_to_learning_queue',
                'time': {
                  'ms': lexicalItemLearningQueueItemJson['added_time_ms'],
                },
                'repetition_number': 0,
              },
            ],
          };
        }

        if (lexicalItemBrainBoostListItemJson != null) {
          lexicalItemMetaJson['progress'] = {
            'type': 'learning',
            'learning_stages': [
              {
                'type': 'suspended',
                'learning_event': 'marked_as_unknown',
                'time': {
                  'ms': lexicalItemBrainBoostListItemJson['added_time_ms'],
                },
                'repetition_number': 0,
              },
            ],
          };
        }
      } else {
        final lexicalItemProgressJson =
            Map.castFrom<dynamic, dynamic, String, dynamic>(lexicalItemProgressMap);

        final progressType = lexicalItemProgressJson['type'];

        if (progressType == 'previously_known') {
          lexicalItemMetaJson['progress'] = {
            'type': 'previously_known',
            'time': {
              'ms': lexicalItemProgressJson['added_time_ms'],
            },
          };
        } else if (progressType == 'learning') {
          final int progress = lexicalItemProgressJson['progress'];

          const repeatIntervals = [
            Duration(hours: 6),
            Duration(hours: 20),
            Duration(hours: 64),
            Duration(hours: 164),
            Duration(hours: 332),
          ];

          final int? repeatTimeMs = lexicalItemProgressJson['repeat_time_ms'];

          int? lastBrainBoostEndTimeMs;
          if (repeatTimeMs != null) {
            lastBrainBoostEndTimeMs = repeatTimeMs - repeatIntervals[progress].inMilliseconds;
          }

          late final List<Map<String, dynamic>> learningStageJsons;
          final answerHistoryItemMaps =
              List.castFrom<dynamic, Map>(lexicalItemProgressJson['answer_history']);

          if (answerHistoryItemMaps.isEmpty) {
            learningStageJsons = [
              {
                'type': 'suspended',
                'learning_event': 'marked_as_unknown',
                'time': {
                  'ms': lexicalItemProgressJson['added_time_ms'],
                },
                'repetition_number': 0,
              },
              {
                'type': 'repeatable',
                'learning_event': 'marked_as_unknown',
                'time': {
                  'ms': lastBrainBoostEndTimeMs!,
                },
                'repetition_number': 0,
              },
            ];
          } else {
            learningStageJsons = [
              {
                'type': 'repeatable',
                'learning_event': 'marked_as_unknown',
                'time': {
                  'ms': lexicalItemProgressJson['added_time_ms'],
                },
                'repetition_number': 0,
              },
            ];

            var repetitionNumber = 0;
            String? previousLearningEvent;

            for (var i = 0; i < answerHistoryItemMaps.length; i++) {
              final answerHistoryItemJson =
                  Map.castFrom<dynamic, dynamic, String, dynamic>(answerHistoryItemMaps[i]);

              final String? answer = answerHistoryItemJson['answer'];

              late String learningEvent;

              if (answer == null) {
                learningEvent = 'marked_as_completely_learned';
              } else if (answer == 'dont_remember') {
                learningEvent = 'marked_as_unremembered';
              }
              if (answer == 'badly_remember') {
                learningEvent = 'marked_as_badly_remembered';
              }
              if (answer == 'remember') {
                learningEvent = 'marked_as_remembered';
              }

              if (learningEvent == 'marked_as_completely_learned') {
                repetitionNumber = 5;
              } else if (learningEvent == 'marked_as_unremembered') {
                repetitionNumber = max(0, repetitionNumber - 1);
              } else if (learningEvent == 'marked_as_badly_remembered') {
                if (previousLearningEvent != 'marked_as_remembered') {
                  repetitionNumber = max(0, repetitionNumber - 1);
                }
              } else if (learningEvent == 'marked_as_remembered') {
                repetitionNumber++;
              }

              final int answerTimeMs = answerHistoryItemJson['time_ms'];

              if (repetitionNumber == 5) {
                learningStageJsons.add({
                  'type': 'suspended',
                  'learning_event': learningEvent,
                  'time': {
                    'ms': answerTimeMs,
                  },
                  'repetition_number': repetitionNumber,
                });
              } else if (i == answerHistoryItemMaps.length - 1) {
                learningStageJsons.add({
                  'type': 'suspended',
                  'learning_event': learningEvent,
                  'time': {
                    'ms': answerTimeMs,
                  },
                  'repetition_number': repetitionNumber,
                });

                if (lexicalItemBrainBoostListItemJson == null && lastBrainBoostEndTimeMs != null) {
                  learningStageJsons.add({
                    'type': 'repeatable',
                    'learning_event': learningEvent,
                    'time': {
                      'ms': lastBrainBoostEndTimeMs,
                    },
                    'repetition_number': repetitionNumber,
                  });
                }
              } else {
                learningStageJsons.add({
                  'type': 'repeatable',
                  'learning_event': learningEvent,
                  'time': {
                    'ms': answerTimeMs,
                  },
                  'repetition_number': repetitionNumber,
                });
              }

              previousLearningEvent = learningEvent;
            }
          }

          lexicalItemMetaJson['progress'] = {
            'type': 'learning',
            'learning_stages': learningStageJsons,
          };
        } else if (progressType == 'excluded') {
          lexicalItemMetaJson['excluded'] = true;
        }
      }

      lexicalItemMetaJson['excluded'] = lexicalItemMetaJson['excluded'] ?? false;

      lexicalItemMetaMap[lexicalItemId] = lexicalItemMetaJson;
    }

    const defaultLexicalItemMetaJson = {
      'excluded': false,
    };

    for (final customLexicalItemJson in customLexicalItemJsons) {
      final lexicalItemId = customLexicalItemJson['id'];
      lexicalItemMetaMap[lexicalItemId] =
          lexicalItemMetaMap[lexicalItemId] ?? defaultLexicalItemMetaJson;
    }

    final collectionMetaMap = backupJson['collections_settings'];

    final customCollectionListItemMaps =
        List.castFrom<dynamic, Map>(backupJson['user_collection_list_items']);

    final customCollectionListItemJsons =
        customCollectionListItemMaps.map((customCollectionListItemMap) {
      final customCollectionListItemJson =
          Map.castFrom<dynamic, dynamic, String, dynamic>(customCollectionListItemMap);

      final customCollectionListItemType = customCollectionListItemJson['type'];

      if (customCollectionListItemType == 'user_collection') {
        final customCollectionJson = customCollectionListItemJson;

        customCollectionJson['type'] = 'custom_collection';

        return customCollectionJson;
      }

      if (customCollectionListItemType == 'user_collection_group') {
        final customCollectionFolerJson = customCollectionListItemJson;

        customCollectionFolerJson['type'] = 'custom_collection_folder';

        final collectionMaps =
            List.castFrom<dynamic, Map>(customCollectionFolerJson['collections']);

        customCollectionFolerJson['collections'] = collectionMaps.map((map) {
          final collectionJson = Map.castFrom<dynamic, dynamic, String, dynamic>(map);

          collectionJson['type'] = 'custom_collection';

          return collectionJson;
        }).toList();

        return customCollectionFolerJson;
      }

      throw Exception();
    }).toList();

    const learningInfoJson = {
      'learning_sessions': [],
    };

    backupJson['lexical_item_meta_map'] = lexicalItemMetaMap;
    backupJson['collection_meta_map'] = collectionMetaMap;
    backupJson['custom_lexical_items'] = customLexicalItemJsons;
    backupJson['custom_collection_list_items'] = customCollectionListItemJsons;
    backupJson['top_level_collection_list_item_ids'] = backupJson['collection_list_item_ids'];
    backupJson['learning_info'] = learningInfoJson;

    backupJson.remove('lexical_items_progress');
    backupJson.remove('brain_boost_list');
    backupJson.remove('learning_queue');
    backupJson.remove('added_to_brain_boost_unknown_lexical_item_times_ms');
    backupJson.remove('user_collection_list_items');
    backupJson.remove('collection_list_item_ids');
    backupJson.remove('collections_settings');
    backupJson.remove('user_words');
    backupJson.remove('interface_language');
    backupJson.remove('theme_mode');
    backupJson.remove('images_allowed');
    backupJson.remove('auto_pronunciation');
    backupJson.remove('tts_config');
    backupJson.remove('trial_expiration_date_ms');
    backupJson.remove('introductory_offer_expiration_date_ms');
    backupJson.remove('alias_settings');
    backupJson.remove('audio_exercise_settings');
    backupJson.remove('training_cards_exercise_settings');
    backupJson.remove('translation_selection_exercise_settings');
    backupJson.remove('typing_exercise_settings');
  });

  return migratedBackupContent;
}
